www.gusucode.com > VC++ 使用图片美化List列表-源码程序 > VC++ 使用图片美化List列表-源码程序/code/ImageListBox.cpp

    //
// ImageListBox.cpp : implementation of CImageListBox class
// Download by http://www.NewXing.com

//
// Author :    GHINI Mauro
//

#include "stdafx.h"

#ifndef __IMAGELISTBOX_H__
#include "ImageListBox.h"
#endif //__IMAGELISTBOX_H__

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// ILB_IMAGE_DATA
//
struct ILB_IMAGE_DATA
{
public:
	int m_nImage;
	DWORD m_dwUserData;

	ILB_IMAGE_DATA()
	{
		m_nImage = -1;
		m_dwUserData = 0;
	};
};

/////////////////////////////////////////////////////////////////////////////
// CImageListBox

BEGIN_MESSAGE_MAP(CImageListBox, CListBox)
	//{{AFX_MSG_MAP(CImageListBox)
	ON_WM_CREATE()
	ON_MESSAGE(WM_SETFONT, OnSetFont)
	ON_MESSAGE(LB_ADDSTRING, OnLBAddString)
	ON_MESSAGE(LB_FINDSTRING, OnLBFindString)
	ON_MESSAGE(LB_FINDSTRINGEXACT, OnLBFindStringExact)
	ON_MESSAGE(LB_GETITEMDATA, OnLBGetItemData)
	ON_MESSAGE(LB_GETTEXT, OnLBGetText)
	ON_MESSAGE(LB_INSERTSTRING, OnLBInsertString)
	ON_MESSAGE(LB_SELECTSTRING, OnLBSelectString)
	ON_MESSAGE(LB_SETITEMDATA, OnLBSetItemData)
	ON_MESSAGE(LB_SETITEMHEIGHT, OnLBSetItemHeight)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

CImageListBox::CImageListBox()
	{ m_pImageList = NULL; }

BOOL CImageListBox::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
	if (!(dwStyle & LBS_OWNERDRAWVARIABLE)) //must be one or the other
		dwStyle |= LBS_OWNERDRAWFIXED;
	return CListBox::Create(dwStyle, rect, pParentWnd, nID);
}

CImageList* CImageListBox::SetImageList(CImageList* pImageList)
{
    ASSERT(pImageList != NULL);

    CImageList* pPrevImageList = m_pImageList;
    m_pImageList = pImageList;
    IMAGEINFO iiImg;
    m_pImageList->GetImageInfo(0, &iiImg);
    m_bmSize.cx = iiImg.rcImage.right;
    m_bmSize.cy = iiImg.rcImage.bottom;

    OnLBSetItemHeight(0, 0);

    return pPrevImageList;
}

CImageList* CImageListBox::GetImageList()
{
    return m_pImageList;
}

int CImageListBox::AddItem(int nImageIndex, DWORD dwItemData)
{
    ASSERT(m_pImageList != NULL);
    if (m_pImageList->GetImageCount() < nImageIndex)
        return LB_ERR;

    char szText[] = "";
    WPARAM wParam = 0;
    LRESULT lResult = DefWindowProc(LB_ADDSTRING, wParam, (LPARAM)szText);
    if (lResult == LB_ERR || lResult == LB_ERRSPACE)
        return lResult;

	ILB_IMAGE_DATA* pState = NULL;
	pState = new ILB_IMAGE_DATA;
    pState->m_nImage = nImageIndex;
	pState->m_dwUserData = dwItemData;
    wParam = (WPARAM)lResult;
    LRESULT lRes = DefWindowProc(LB_SETITEMDATA, wParam, (LPARAM)pState);

	if (lRes == LB_ERR && pState != NULL)
		delete pState;

	return lResult;
}

void CImageListBox::MeasureItem(LPMEASUREITEMSTRUCT)
{
	// You must override DrawItem and MeasureItem for LBS_OWNERDRAWVARIABLE
	ASSERT((GetStyle() & (LBS_OWNERDRAWFIXED | LBS_HASSTRINGS)) ==
		(LBS_OWNERDRAWFIXED | LBS_HASSTRINGS));
}

void CImageListBox::PreDrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	DRAWITEMSTRUCT drawItem;
	memcpy(&drawItem, lpDrawItemStruct, sizeof(DRAWITEMSTRUCT));

	if ((((LONG)drawItem.itemID) >= 0) &&
	   ((drawItem.itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) != 0))
	{
		int cyItem = GetItemHeight(drawItem.itemID);

		CDC* pDC = CDC::FromHandle(drawItem.hDC);
		COLORREF newBkColor = GetSysColor(COLOR_WINDOW);

		BOOL fDisabled = !IsWindowEnabled();
		if ((drawItem.itemState & ODS_SELECTED) && !fDisabled)
			newBkColor = GetSysColor(COLOR_HIGHLIGHT);

		COLORREF oldBkColor = pDC->SetBkColor(newBkColor);

		CDC bitmapDC;
		if (bitmapDC.CreateCompatibleDC(pDC))
		{
            ILB_IMAGE_DATA* pState = (ILB_IMAGE_DATA*)lpDrawItemStruct->itemData;

			CRect rectImage = drawItem.rcItem;
			rectImage.left += 1 + max(0, (rectImage.right - m_bmSize.cx) / 2);
			rectImage.top += 1 + max(0, (cyItem - m_bmSize.cy) / 2);
			rectImage.right = rectImage.left + m_bmSize.cx;
			rectImage.bottom = rectImage.top + m_bmSize.cy;

			CBrush brush(newBkColor);
			pDC->FillRect(&(drawItem.rcItem), &brush);

            POINT pt;
            pt.x = rectImage.left;
            pt.y = rectImage.top;
            m_pImageList->Draw(pDC, pState->m_nImage, pt, ILD_NORMAL);
		}
		pDC->SetBkColor(oldBkColor);
	}

	if ((drawItem.itemAction & ODA_FOCUS) != 0)
    {
        CDC* pDC = CDC::FromHandle(drawItem.hDC);
		pDC->DrawFocusRect(&(drawItem.rcItem));
    }
}

void CImageListBox::PreMeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	int cyItem = CalcMinimumItemHeight();

	MEASUREITEMSTRUCT measureItem;
	memcpy(&measureItem, lpMeasureItemStruct, sizeof(MEASUREITEMSTRUCT));

	measureItem.itemHeight = cyItem;
	measureItem.itemWidth  = (UINT)-1;

	// WINBUG: Windows95 and Windows NT disagree on what this value
	// should be.  According to the docs, they are both wrong
	if (GetStyle() & LBS_OWNERDRAWVARIABLE)
	{
		LRESULT lResult = DefWindowProc(LB_GETITEMDATA, measureItem.itemID, 0);
		if (lResult != LB_ERR)
			measureItem.itemData = (UINT)lResult;
		else
			measureItem.itemData = 0;

		// WINBUG: This is only done in the LBS_OWNERDRAWVARIABLE case
		// because Windows 95 does not initialize itemData to zero in the
		// case of LBS_OWNERDRAWFIXED list boxes (it is stack garbage).
		if (measureItem.itemData != 0)
		{
			ILB_IMAGE_DATA* pState = (ILB_IMAGE_DATA*)measureItem.itemData;
			measureItem.itemData = pState->m_dwUserData;
		}
	}

	MeasureItem(&measureItem);

	lpMeasureItemStruct->itemHeight = max(measureItem.itemHeight,(UINT) cyItem);
	lpMeasureItemStruct->itemWidth = measureItem.itemWidth;
}

int CImageListBox::PreCompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct)
{
	COMPAREITEMSTRUCT compareItem;
	memcpy(&compareItem, lpCompareItemStruct, sizeof(COMPAREITEMSTRUCT));

	if (compareItem.itemData1 != 0)
	{
		ILB_IMAGE_DATA* pState = (ILB_IMAGE_DATA*)compareItem.itemData1;
		compareItem.itemData1 = pState->m_dwUserData;
	}
	if (compareItem.itemData2 != 0)
	{
		ILB_IMAGE_DATA* pState = (ILB_IMAGE_DATA*)compareItem.itemData2;
		compareItem.itemData2 = pState->m_dwUserData;
	}
	return CompareItem(&compareItem);
}

void CImageListBox::PreDeleteItem(LPDELETEITEMSTRUCT lpDeleteItemStruct)
{
	DELETEITEMSTRUCT deleteItem;
	memcpy(&deleteItem, lpDeleteItemStruct, sizeof(DELETEITEMSTRUCT));

	// WINBUG: The following if block is required because Windows NT
	// version 3.51 does not properly fill out the LPDELETEITEMSTRUCT.
	if (deleteItem.itemData == 0)
	{
		LRESULT lResult = DefWindowProc(LB_GETITEMDATA, deleteItem.itemID, 0);
		if (lResult != LB_ERR)
			deleteItem.itemData = (UINT)lResult;
	}

	if (deleteItem.itemData != 0)
	{
		ILB_IMAGE_DATA* pState = (ILB_IMAGE_DATA*)deleteItem.itemData;
		deleteItem.itemData = pState->m_dwUserData;
		delete pState;
	}
	DeleteItem(&deleteItem);
}

BOOL CImageListBox::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam,
	LRESULT* pResult)
{
	switch (message)
	{
	case WM_DRAWITEM:
		ASSERT(pResult == NULL);       // no return value expected
		PreDrawItem((LPDRAWITEMSTRUCT)lParam);
		break;
	case WM_MEASUREITEM:
		ASSERT(pResult == NULL);       // no return value expected
		PreMeasureItem((LPMEASUREITEMSTRUCT)lParam);
		break;
	case WM_COMPAREITEM:
		ASSERT(pResult != NULL);       // return value expected
		*pResult = PreCompareItem((LPCOMPAREITEMSTRUCT)lParam);
		break;
	case WM_DELETEITEM:
		ASSERT(pResult == NULL);       // no return value expected
		PreDeleteItem((LPDELETEITEMSTRUCT)lParam);
		break;
	default:
		return CListBox::OnChildNotify(message, wParam, lParam, pResult);
	}
	return TRUE;
}

#ifdef _DEBUG
void CImageListBox::PreSubclassWindow()
{
	CListBox::PreSubclassWindow();

	// CImageListBoxes must be owner drawn
	ASSERT(GetStyle() & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE));
}
#endif

int CImageListBox::CalcMinimumItemHeight()
{
	return m_bmSize.cy + 3;
}

int CImageListBox::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CListBox::OnCreate(lpCreateStruct) == -1)
		return -1;

	if ((GetStyle() & (LBS_OWNERDRAWFIXED | LBS_HASSTRINGS))
		== (LBS_OWNERDRAWFIXED | LBS_HASSTRINGS))
		SetItemHeight(0, CalcMinimumItemHeight());

	return 0;
}

LRESULT CImageListBox::OnSetFont(WPARAM , LPARAM)
{
	Default();
	return 0;
}

LRESULT CImageListBox::OnLBAddString(WPARAM wParam, LPARAM lParam)
{
	return LB_ERR;
}

LRESULT CImageListBox::OnLBFindString(WPARAM wParam, LPARAM lParam)
{
	return LB_ERR;
}

LRESULT CImageListBox::OnLBFindStringExact(WPARAM wParam, LPARAM lParam)
{
	return LB_ERR;
}

LRESULT CImageListBox::OnLBGetItemData(WPARAM wParam, LPARAM lParam)
{
	LRESULT lResult = DefWindowProc(LB_GETITEMDATA, wParam, lParam);

	if (lResult != LB_ERR)
	{
		ILB_IMAGE_DATA* pState = (ILB_IMAGE_DATA*)lResult;

		if (pState == NULL)
			return 0; // default

		lResult = pState->m_dwUserData;
	}
	return lResult;
}

LRESULT CImageListBox::OnLBSetItemData(WPARAM wParam, LPARAM lParam)
{
	LRESULT lResult = DefWindowProc(LB_GETITEMDATA, wParam, 0);

	if (lResult != LB_ERR)
	{
		ILB_IMAGE_DATA* pState = (ILB_IMAGE_DATA*)lResult;

		if (pState == NULL)
			pState = new ILB_IMAGE_DATA;

		pState->m_dwUserData = lParam;
		lResult = DefWindowProc(LB_SETITEMDATA, wParam, (LPARAM)pState);

		if (lResult == LB_ERR)
			delete pState;
	}
	return lResult;
}

LRESULT CImageListBox::OnLBGetText(WPARAM wParam, LPARAM lParam)
{
	return LB_ERR;
}

LRESULT CImageListBox::OnLBInsertString(WPARAM wParam, LPARAM lParam)
{
	return LB_ERR;
}

LRESULT CImageListBox::OnLBSelectString(WPARAM wParam, LPARAM lParam)
{
	return LB_ERR;
}

LRESULT CImageListBox::OnLBSetItemHeight(WPARAM wParam, LPARAM lParam)
{
	int nHeight = max(CalcMinimumItemHeight(),(int)LOWORD(lParam));
	return DefWindowProc(LB_SETITEMHEIGHT, wParam, MAKELPARAM(nHeight,0));
}

IMPLEMENT_DYNAMIC(CImageListBox, CListBox)


/////////////////////////////////////////////////////////////////////////////